package com.nineclock.system.service.impl;

import java.util.*;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.filter.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.system.dto.*;
import com.nineclock.system.excel.ExcelMember;
import com.nineclock.system.excel.ExcelMemberListener;
import com.nineclock.system.mapper.*;
import com.nineclock.system.pojo.*;
import com.nineclock.system.service.SysCompanyUserService;
import lombok.extern.slf4j.Slf4j;
import com.nineclock.system.sy.SysCompanyUserDTOS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
@Slf4j
public class SysCompanyUserServiceImpl implements SysCompanyUserService {

    @Autowired(required = false)
    private SysCompanyUserMapper companyUserMapper;

    @Autowired(required = false)
    private SysRoleMapper roleMapper;

    @Autowired(required = false)
    private SysDepartmentMapper departmentMapper;

    @Autowired(required = false)
    private SysUserMapper userMapper;

    @Autowired(required = false)
    private SysCompanyUserRoleMapper companyUserRoleMapper;
    @Autowired
    private SysRoleFunctionMapper roleFunctionMapper;
    @Autowired
    private SysFunctionMapper functionMapper;

    @Override
    public List<SysCompanyUserDTO> queryCompanyUser(Long userId, Long companyId) {
        // 根据用户id、公司id查询对应员工列表
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getUserId, userId);
        if (companyId != null) {
            wrapper.eq(SysCompanyUser::getCompanyId, companyId);
        }
        List<SysCompanyUser> companyUserList = companyUserMapper.selectList(wrapper);

        if (CollectionUtils.isEmpty(companyUserList)) {
            throw new NcException(ResponseEnum.USER_NOT_JOIN_COMPANY);
        }

        // 数据转换，List<SysCompanyUser>  --> List<SysCompanyUserDTO>
        List<SysCompanyUserDTO> companyUserDTOList = BeanHelper.copyWithCollection(companyUserList, SysCompanyUserDTO.class);

        // 遍历员工列表，查询每个员工对应的角色、权限信息
        List<SysFunctionDTO> functionDTOS = new ArrayList<>();

        for (SysCompanyUserDTO companyUserDTO : companyUserDTOList) {
            // 获取员工id
            Long companyUserId = companyUserDTO.getId();

            // 根据员工id，查询对应的角色信息
            List<SysRole> roleList = roleMapper.queryRoleByCompanyUserId(companyUserId);

            if (!CollectionUtils.isEmpty(roleList)) {
                // 数据转换
                List<SysRoleDTO> roleDTOList = BeanHelper.copyWithCollection(roleList, SysRoleDTO.class);
                companyUserDTO.setRoles(roleDTOList);
            }

            // TODO 根据角色id集合查询对应的权限信息

          /*  for (SysRole sysRole : roleList) {

                LambdaQueryWrapper<SysRoleFunction> wrapper1 = new LambdaQueryWrapper<>();
                wrapper1.eq(SysRoleFunction::getRoleId,sysRole.getId());

                List<SysRoleFunction> sysRoleFunctionList = roleFunctionMapper.selectList(wrapper1);
                for (SysRoleFunction sysRoleFunction : sysRoleFunctionList) {

                    SysFunction sysFunction = functionMapper.selectById(sysRoleFunction.getFunctionId());
                    functionDTOS.add(BeanHelper.copyProperties(sysFunction,SysFunctionDTO.class));

                }

            }
            List<SysFunctionDTO> sysFunctionDTOList = functionDTOS.stream().distinct().collect(Collectors.toList());
            for (SysFunctionDTO sysFunction : sysFunctionDTOList) {
                log.info(sysFunction.getTitle());
            }
            if (!CollectionUtils.isEmpty(sysFunctionDTOList)){
                companyUserDTO.setFunctions(sysFunctionDTOList);
            }*/
        }

        return companyUserDTOList;
    }

    @Override
    public SysCompanyUserDTO getCurrentAdmin() {
        // 获取当前登录用户所属企业id
        Long companyId = CurrentUserHolder.get().getCompanyId();

        // 查询当前企业的主管理员
        SysCompanyUser companyUser = companyUserMapper.queryMainAdminCompanyUser(companyId);

        if (companyUser == null) {
            throw new NcException(ResponseEnum.COMPANY_ADMIN_NOT_EXISTS);
        }

        return BeanHelper.copyProperties(companyUser, SysCompanyUserDTO.class);
    }

    @Override
    public List<SysCompanyUserDTO> queryCompanyMemberList() {
        // 获取当前登录用户所属的企业id
        Long companyId = CurrentUserHolder.get().getCompanyId();

        // 根据企业id查询员工表，得到该企业所有的员工列表
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId, companyId);
        wrapper.eq(SysCompanyUser::getEnable, 1);
        List<SysCompanyUser> companyUserList = companyUserMapper.selectList(wrapper);

        // 数据转换
        List<SysCompanyUserDTO> companyUserDTOList = BeanHelper.copyWithCollection(companyUserList, SysCompanyUserDTO.class);

        return companyUserDTOList;
    }

    @Override
    public SysCompanyUserDTO queryCompanyUserById(Long companyUserId) {
        SysCompanyUser companyUser = companyUserMapper.selectById(companyUserId);
        SysCompanyUserDTO companyUserDTO = BeanHelper.copyProperties(companyUser, SysCompanyUserDTO.class);
        return companyUserDTO;
    }

    @Override
    public List<SysCompanyUserDTO> queryAllCompanyUser() {

        Long companyId = CurrentUserHolder.get().getCompanyId();

        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId, companyId);
        wrapper.eq(SysCompanyUser::getEnable, 1);

        List<SysCompanyUser> companyUserList = companyUserMapper.selectList(wrapper);

        return BeanHelper.copyWithCollection(companyUserList, SysCompanyUserDTO.class);
    }

    @Override
    public PageResult<SysCompanyUserDTO> queryMembers(Integer page, Integer pageSize, Long departmentId, String keyword) {

        // 构造查询条件
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId, CurrentUserHolder.get().getCompanyId());

        if (departmentId != null) {
            // 递归查询所有下级部门的id集合
            List<Long> deptIdList = new ArrayList<>();
            deptIdList.add(departmentId);
            queryAllChildDeparmentIds(deptIdList, departmentId);
            wrapper.in(SysCompanyUser::getDepartmentId, deptIdList);
        }

        if (!StringUtils.isEmpty(keyword)) {
            // where companyId = 1 and (username like xxx or workNumber like xxx or mobile like xxx)
            wrapper.and(w -> w.like(SysCompanyUser::getUserName, keyword)
                    .or()
                    .like(SysCompanyUser::getWorkNumber, keyword)
                    .or()
                    .like(SysCompanyUser::getMobile, keyword)
            );
        }

        // 创建分页对象
        IPage<SysCompanyUser> ipage = new Page<>(page, pageSize);
        ipage = companyUserMapper.selectPage(ipage, wrapper);

        // 获取当前页数据
        List<SysCompanyUser> companyUserList = ipage.getRecords();

        if (!CollectionUtils.isEmpty(companyUserList)) {

            List<SysCompanyUserDTO> companyUserDTOList = BeanHelper.copyWithCollection(companyUserList, SysCompanyUserDTO.class);

            for (SysCompanyUserDTO companyUserDTO : companyUserDTOList) {
                // 额外设置department属性，因为前端需要
                SysDepartmentDTO departmentDTO = new SysDepartmentDTO();
                departmentDTO.setId(companyUserDTO.getDepartmentId());
                departmentDTO.setName(companyUserDTO.getDepartmentName());
                companyUserDTO.setDepartment(departmentDTO);
            }

            return new PageResult<>(ipage.getTotal(), ipage.getPages(), companyUserDTOList);
        }

        return new PageResult<>(ipage.getTotal(), ipage.getPages(), null);
    }

    /**
     * 递归查询某部门下的所有部门id集合
     *
     * @param deptIdList
     * @param departmentId
     */
    private void queryAllChildDeparmentIds(List<Long> deptIdList, Long departmentId) {

        LambdaQueryWrapper<SysDepartment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDepartment::getCompanyId, CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SysDepartment::getParentId, departmentId);

        List<SysDepartment> departmentList = departmentMapper.selectList(wrapper);

        if (!CollectionUtils.isEmpty(departmentList)) {
            // 遍历子部门列表
            for (SysDepartment department : departmentList) {

                queryAllChildDeparmentIds(deptIdList, department.getId());

                deptIdList.add(department.getId());
            }
        }

    }


    @Override
    public void importData(MultipartFile excelFile) throws Exception {
        // A. 通过SpringMVC接收上传上来的文件，并对文件进行健壮性判断
        if (excelFile == null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        // B. 通过EasyExcel来解析Excel文件，获取文件内容
        EasyExcel.read(excelFile.getInputStream(), ExcelMember.class,
                new ExcelMemberListener(this)).sheet(0).doRead();

    }



    @Override
    public void handleParsedData(List<ExcelMember> memberList) {
        for (ExcelMember excelMember : memberList) {
            // C. 保存系统用户数据，需要判定手机号、邮箱是否已经被注册；判定员工工号是否被占用；
            pendingMobileAndEmailAndWorkNumer(excelMember);

            // 保存用户数据
            SysUser sysUser = new SysUser();
            sysUser.setUsername(excelMember.getName());
            sysUser.setPassword(new BCryptPasswordEncoder().encode("123456"));
            sysUser.setMobile(excelMember.getMobile());
            sysUser.setEmail(excelMember.getEmail());
            sysUser.setCreateTime(new Date());
            sysUser.setUpdateTime(new Date());
            sysUser.setStatus((short) (excelMember.getEnable().equals("可用") ? 1 : 0));
            sysUser.setLastLoginCompanyId(CurrentUserHolder.get().getCompanyId());
            userMapper.insert(sysUser);

            // D. 保存企业员工数据
            Long companyUserId = saveCompanyUser(excelMember, sysUser);

            // E. 维护企业员工关联的角色
            saveCompanyUserRole(excelMember, companyUserId);

        }
    }


    /**
     * 保存员工角色关系表
     * @param excelMember
     * @param companyUserId
     */
    private void saveCompanyUserRole(ExcelMember excelMember, Long companyUserId) {
        SysCompanyUserRole companyUserRole = new SysCompanyUserRole();
        companyUserRole.setCompanyUserId(companyUserId);
        companyUserRole.setCompanyId(CurrentUserHolder.get().getCompanyId());

        LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysRole::getCompanyId, CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SysRole::getRoleDesc, excelMember.getRoleName());
        SysRole sysRole = roleMapper.selectOne(wrapper);

        if (sysRole != null) {
            companyUserRole.setRoleId(sysRole.getId());
            companyUserRoleMapper.insert(companyUserRole);
        }
    }

    /**
     * 保存员工数据
     * @param excelMember
     */
    private Long saveCompanyUser(ExcelMember excelMember, SysUser user) {
        SysCompanyUser sysCompanyUser = new SysCompanyUser();
        sysCompanyUser.setUserId(user.getId());
        sysCompanyUser.setCompanyId(CurrentUserHolder.get().getCompanyId());
        sysCompanyUser.setCompanyName(CurrentUserHolder.get().getCompanyName());
        sysCompanyUser.setPost(excelMember.getPosition());
        sysCompanyUser.setWorkNumber(excelMember.getWorkNumber());
        sysCompanyUser.setEmail(excelMember.getEmail());
        sysCompanyUser.setOfficeAddress(excelMember.getWorkAddr());
        sysCompanyUser.setTimeEntry(new Date());
        sysCompanyUser.setRemark(excelMember.getDesc());
        sysCompanyUser.setEnable((short) (excelMember.getEnable().equals("可用") ? 1 : 0));
        sysCompanyUser.setCreateTime(new Date());
        sysCompanyUser.setUpdateTime(new Date());
        sysCompanyUser.setMobile(excelMember.getMobile());
        sysCompanyUser.setUserName(excelMember.getName());

        // 根据部门名称查询部门信息
        LambdaQueryWrapper<SysDepartment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDepartment::getCompanyId, CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SysDepartment::getName, excelMember.getDepartmentName());
        SysDepartment department = departmentMapper.selectOne(wrapper);

        if (department != null) {
            sysCompanyUser.setDepartmentId(department.getId());
            sysCompanyUser.setDepartmentName(department.getName());
        }
        companyUserMapper.insert(sysCompanyUser);
        return sysCompanyUser.getId();
    }

    /**
     * 判定手机号、邮箱是否已经被注册；判定员工工号是否被占用
     * @param excelMember
     */
    private void pendingMobileAndEmailAndWorkNumer(ExcelMember excelMember) {

        // 判断手机号或邮箱是否存在
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId, CurrentUserHolder.get().getCompanyId());
        // where mobile = xxx or email = xxx
        wrapper.and(w -> w.eq(SysCompanyUser::getMobile, excelMember.getMobile())
                .or()
                .eq(SysCompanyUser::getEmail, excelMember.getEmail())
        );

        Integer count = companyUserMapper.selectCount(wrapper);

        if (count > 0) {
            throw new NcException(ResponseEnum.USER_MOBILE_EMAIL_EXISTS);
        }

        // 判断工号是否存在
        LambdaQueryWrapper<SysCompanyUser> wrapper2 = new LambdaQueryWrapper<>();
        wrapper2.eq(SysCompanyUser::getCompanyId, CurrentUserHolder.get().getCompanyId());
        wrapper2.eq(SysCompanyUser::getWorkNumber, excelMember.getWorkNumber());

        Integer count2 = companyUserMapper.selectCount(wrapper2);

        if (count2 > 0) {
            throw new NcException(ResponseEnum.WROK_NUM_EXISTS);
        }

    }


    @Override
    public SysCompanyUserDTO queryOne(String mobile) {
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId, CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SysCompanyUser::getMobile, mobile);

        SysCompanyUser companyUser = companyUserMapper.selectOne(wrapper);
        return BeanHelper.copyProperties(companyUser, SysCompanyUserDTO.class);
    }

    @Override
    public Integer queryUserCountByDepartmentIds(List<Long> departmentIds) {
        // 查询部门下的子部门id集合
        List<Long> idList = new ArrayList<>();
        idList.addAll(departmentIds);

        for (Long departmentId : departmentIds) {
            this.queryAllChildDeparmentIds(idList, departmentId);
        }

        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId, CurrentUserHolder.get().getCompanyId());
        wrapper.in(SysCompanyUser::getDepartmentId, departmentIds);
        wrapper.eq(SysCompanyUser::getEnable, 1);
        Integer count = companyUserMapper.selectCount(wrapper);
        return count;
    }

    @Override
    public List<SysCompanyUserDTO> queryAllUserByCompanyId(Long companyId) {
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId, companyId);
        wrapper.eq(SysCompanyUser::getEnable, 1);
        List<SysCompanyUser> companyUserList = companyUserMapper.selectList(wrapper);

        if(!CollectionUtils.isEmpty(companyUserList)){
            return BeanHelper.copyWithCollection(companyUserList, SysCompanyUserDTO.class);
        }
        return null;
    }

    @Override
    public SysCompanyUserDTO queryAdminByCompanyId(Long companyId) {
        SysCompanyUser companyUser = companyUserMapper.queryMainAdminCompanyUser(companyId);
        return BeanHelper.copyProperties(companyUser, SysCompanyUserDTO.class);
    }

    @Override
    public void updateDepartment(SysDepartmentUserDTO departmentUserDTO) {
        List<SysCompanyUserDTO> users = departmentUserDTO.getUsers();
        List<Long> companyIdList = new ArrayList<>();
        for (SysCompanyUserDTO user : users) {
            Long id = user.getId();
            companyIdList.add(id);
        }

        Long departmentId = departmentUserDTO.getDepartment().getId();
        SysDepartment sysDepartment = departmentMapper.selectById(departmentId);
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(SysCompanyUser::getId,companyIdList);
        SysCompanyUser sysCompanyUser = new SysCompanyUser();
        sysCompanyUser.setDepartmentId(departmentUserDTO.getDepartment().getId());
        sysCompanyUser.setDepartmentName(sysDepartment.getName());
        companyUserMapper.update(sysCompanyUser,wrapper);
    }

    /**
     * 接口名称：组织架构:删除部门成员
     * 接口路径：DELETE/sys/organization/members
     * @param departmentUserDTO
     */
    @Override
    public void removeCompanyUser(SysDepartmentUserDTO departmentUserDTO) {
        if (departmentUserDTO == null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        List<Long> ids = new ArrayList<>();
        for (String id : departmentUserDTO.getIds()) {
            ids.add(Long.valueOf(id));
        }
        wrapper.in(SysCompanyUser::getId,ids);
        companyUserMapper.delete(wrapper);
    }

    @Override
    public SysCompanyUserDTO addCompanyUser(SysCompanyUserDTOS companyUserDTOS) {


        if (companyUserDTOS==null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        LambdaQueryWrapper<SysCompanyUser> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId,CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SysCompanyUser::getMobile,companyUserDTOS.getMobile());
        SysCompanyUser sysCompanyUser = companyUserMapper.selectOne(wrapper);

        if (sysCompanyUser==null){
            throw new NcException(ResponseEnum.USER_NOT_FOUND);
        }
        sysCompanyUser.setPost(companyUserDTOS.getPost());
        sysCompanyUser.setDepartmentId(companyUserDTOS.getDepartment().getId());
        sysCompanyUser.setWorkNumber(companyUserDTOS.getWorkNumber());
        sysCompanyUser.setEmail(companyUserDTOS.getEmail());


        SysDepartment sysDepartment = departmentMapper.selectById(companyUserDTOS.getDepartment().getId());
        sysCompanyUser.setDepartmentName(sysDepartment.getName());

        companyUserMapper.updateById(sysCompanyUser);

        return BeanHelper.copyProperties(sysCompanyUser,SysCompanyUserDTO.class);

    }


    /**
     * 根据关键字(姓名、工号、部门)查询企业相关人员ids
     */
    public List<Long> queryByKeyword(String keyword) {
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId, CurrentUserHolder.get().getCompanyId());
        wrapper.and(w -> w.like(SysCompanyUser::getUserName,keyword)
                .or()
                .like(SysCompanyUser::getDepartmentName,keyword)
                .or()
                .like(SysCompanyUser::getWorkNumber,keyword));
        List<SysCompanyUser> companyUserList = companyUserMapper.selectList(wrapper);

        List<Long> ids = companyUserList.stream().map(SysCompanyUser::getId).collect(Collectors.toList());
        return ids;
    }

}
